#include "site.h"

Site::Site(const char *domain,  long double link_bw) {
	this->processorAvailableInformation = true;
	this->networkAvailableInformation = true;	
	
	this->domain = new char[strlen(domain)+1];
	this->domain = strcpy((char *)this->domain, domain);
	
	this->numberOfProcessors = 0;
	this->processors = NULL;
	/*Instantiate a storage*/
	char *storage_name = new char[strlen(this->domain)+9];	
	sprintf(storage_name, "storage_%s", this->domain);
	this->storage = new Storage(storage_name);
	delete storage_name;
	/*Instantiate a intra-site link. The latency is considered negligible*/
	char *link_name = new char[strlen(this->domain)+11];	
	sprintf(link_name, "intralink_%s", this->domain);
	this->link = new Link(link_name,Link::MINIMUM_LATENCY,link_bw, link_bw);
	delete link_name;
}

Site::Site(const char *domain, const char *link_bw, long double link_bw_offset, const char *bw_error, const char *link_bw_forecast) {
	if (( link_bw_forecast!=NULL && FileChecker::verify(link_bw_forecast)) || FileChecker::verify(link_bw) )
		throw std::runtime_error("Cannot open link trace file");
		
	this->processorAvailableInformation = true;
	this->networkAvailableInformation = true;
	
	this->domain = new char[strlen(domain)+1];
	this->domain = strcpy((char *)this->domain, domain);

	this->numberOfProcessors = 0;
	this->processors = NULL;
	/*Instantiate a storage*/
	char *storage_name = new char[strlen(this->domain)+9];	
	sprintf(storage_name, "storage_%s", this->domain);
	this->storage = new Storage(storage_name);
	delete storage_name;
	/*Instantiate a intra-site link. The latency is considered negligible*/
	char *link_name = new char[strlen(this->domain)+11];	
	sprintf(link_name, "intralink_%s", this->domain);
	this->link = new Link(link_name, NULL, 0, link_bw, link_bw_offset, link_bw, link_bw_offset, NULL, bw_error, NULL, link_bw_forecast, link_bw_forecast);
	delete link_name;
}

Site::~Site() {
	if (link!=NULL) {
		delete link;
		this->link = NULL;		
	}
	if (storage!=NULL) {
		delete storage;
		this->storage = NULL;
	}
	
	for (int n = 0; n< this->numberOfProcessors; n++) {
		if (this->processors[n]!=NULL) {
			delete this->processors[n];
			this->processors[n] = NULL;
		}
	}

	if (this->domain) delete this->domain;
}

const char *Site::getDomain() {
	return this->domain;
}

void Site::addProcessor( long double relSpeed, const char *cpu_avail_trace, long double cpu_offset, const char *cpu_avail_error, const char *cpu_avail_forecast) {
	if ((cpu_avail_forecast!=NULL) && FileChecker::verify(cpu_avail_forecast)) {
		throw std::runtime_error("Cannot open cpu forecast file");
	}
	
	if (FileChecker::verify(cpu_avail_trace)) {
		throw std::runtime_error("Cannot open cpu trace file");
	}
	
	if (FileChecker::verify(cpu_avail_error)) {
		throw std::runtime_error("Cannot open cpu error file");
	}
		
	char *proc_name = new char[80];
	this->numberOfProcessors++;
	/*Reallocate the memory used by the array of processors*/
	this->processors = (Processor **) realloc(this->processors, this->numberOfProcessors*sizeof(Processor *));
	/*Instantiate the new processor*/
	sprintf(proc_name, "processor_%d_%s", this->numberOfProcessors, this->domain);
	this->processors[numberOfProcessors - 1] = new Processor(proc_name, relSpeed, cpu_avail_trace, cpu_offset, cpu_avail_error, cpu_avail_forecast);
	delete proc_name;
}

void Site::addProcessor( long double relSpeed, long double fixed_cpu) {
	char *proc_name = new char[80];
	this->numberOfProcessors++;
	/*Reallocate the memory used by the array of processors*/
	this->processors = (Processor **) realloc(this->processors, this->numberOfProcessors*sizeof(Processor *));
	/*Instantiate the new processor*/
	sprintf(proc_name, "processor_%d_%s", this->numberOfProcessors, this->domain);
	this->processors[numberOfProcessors - 1] = new Processor(proc_name, relSpeed, fixed_cpu);
	delete proc_name;
}

Processor *Site::getProcessorByIndex(int index) {
	return this->processors[index];
}

Processor *Site::getProcessorByName(const char *name) {
	Processor *proc= NULL;
	for (int n=0; n<this->numberOfProcessors; n++) {
		if (!strcmp(name, this->getProcessorByIndex(n)->getName())) {
			proc = this->getProcessorByIndex(n);
		}
	}
	
	if (proc==NULL) throw std::runtime_error("Processor does not exist in this site");	
	return proc;
}

int Site::getNumberOfProcessors() {
	return this->numberOfProcessors;
}

Link *Site::getLink() {
	return this->link;
}

Storage *Site::getStorage() {
	return this->storage;
}

bool Site::hasData(DataElement *data) {
	return (this->getStorage()->existDataElement(data->getName())!=NULL);
}

bool Site::allProcessorsAreBusy() {
	bool busy = true;
	for (int n = 0; n < this->getNumberOfProcessors(); n++) {
		if (!this->getProcessorByIndex(n)->isBusy()) {
			busy = false;
			break;
		}
	}
	return busy;
}

int Site::getNumberOfAllocatedTasks() {
	int numberOfTasks = 0;;
	for (int p = 0; p< this->numberOfProcessors; p++) {
		numberOfTasks+=this->getProcessorByIndex(p)->getNumberOfAllocatedTasks();
	} 
	return numberOfTasks;
}

void Site::setAllInformationAvailable() {
	setProcessorInformationAvailable();
	setNetworkInformationAvailable();
}

void Site::setAllInformationNotAvailable() {
	setProcessorInformationNotAvailable();
	setNetworkInformationNotAvailable();
}

void Site::setProcessorInformationAvailable() {
	this->processorAvailableInformation = true;
}

void Site::setProcessorInformationNotAvailable() {
	this->processorAvailableInformation = false;
}

void Site::setNetworkInformationAvailable() {
	this->networkAvailableInformation = true;
}

void Site::setNetworkInformationNotAvailable() {
	this->networkAvailableInformation = false;
}

bool Site::hasAllAvailableInformation() {
	return ( (this->processorAvailableInformation) && (this->networkAvailableInformation) );
}

bool Site::hasProcessorAvailableInformation() {
	return (this->processorAvailableInformation);
}

bool Site::hasNetworkAvailableInformation() {
	return (this->networkAvailableInformation);
}

